/* Include files. */

#include "standard.h"
#include "debug.h"

/* Local function declarations. */

/* Macro API definitions. */

//#define FILE_LOG

#ifdef FILE_LOG
#define MU_LOG_FILE   	"/var/log/mulog"
#else
#define MU_LOG_FILE   	"/dev/console"
#endif

#define PRINT_LEN 			(1024 * 12)
#define FUN_LINE_FORMAT		"[%17s:%-5d]" 
#define FUN_LINE_LUA_FORMAT	CON_COLOR_CYAN "[%17s:%-5d]" CON_COLOR_END
#define FILENAME(x) 		(strrchr(x,'/')?strrchr(x,'/')+1:x)

/* Global variable declarations. */

static int log_fd = -1;
static int cur_stdout = -1;
static int cur_stderr = -1;
static int debug_level = 0;
static int debug_lua_level = 0;

/* Type definitions. */

/* Local function definitions. */

static int looFileOpen()
{
	int fd = open(MU_LOG_FILE, (O_RDWR | O_CREAT), 0644);
	if (fd < 0) {
		ERROR("Open log file fialed: %s.\n", strerror(errno));
		return -1;
	}
	return fd;
}

static void logFileWrite()
{
	if (log_fd < 0) {
		if ((log_fd = looFileOpen()) < 0) {
			return;
		}
	}

	cur_stdout = dup(STDOUT_FILENO);
	cur_stderr = dup(STDERR_FILENO);

#ifdef FILE_LOG
	dup2(log_fd, STDOUT_FILENO);
	dup2(log_fd, STDERR_FILENO);
#endif

}

void logFileClose()
{
	if (log_fd > 0) {
		close(log_fd);
	}
	
	log_fd = -1;
	
	close(cur_stdout);
	close(cur_stderr);
	
#ifdef FILE_LOG	
	dup2(cur_stdout, STDOUT_FILENO);
	dup2(cur_stderr, STDERR_FILENO);
#endif

	return;
}

static inline void getTime(char *buff, int buff_len)
{
	struct timeval tv = {0};
	struct tm *time_v = NULL, time_value = {0};

	gettimeofday(&tv,NULL);
	time_v = localtime_r(&tv.tv_sec, &time_value);

	if(NULL != time_v) {
		snprintf(buff,buff_len, "%02d/%02d %02d:%02d:%02d", \
				 time_v->tm_mon+1, \
				 time_v->tm_mday, time_v->tm_hour, \
				 time_v->tm_min, time_v->tm_sec);
	}
}

int muPrint(FILE *fp, int level, const char *file, 
					const int line, const char *fmt, ...)
{
	va_list args;
	static __thread char buf[PRINT_LEN];
	int i = 0;
	char time[64];

	if (NULL == fp)
		return -1;
	
	if ((e_ERR == level)
		||(debug_level <= level))
	{
		getTime(time, sizeof(time));
		va_start(args, fmt);
		i = vsnprintf(buf, PRINT_LEN, fmt, args);
		va_end(args);
		
		switch (level) {
			case e_DEBUG:
				fprintf(fp, "%s" FUN_LINE_FORMAT CON_COLOR_GREEN "[DEBUG] " CON_COLOR_END \
						  "%s", time, FILENAME(file), (line), buf);
				break;		
				
			case e_INFO:
				fprintf(fp, "%s" FUN_LINE_FORMAT CON_COLOR_YELLOW "[ INFO] " CON_COLOR_END \
						  "%s", time, FILENAME(file), (line), buf);
				break;
			case e_WARN:
				fprintf(fp, "%s" FUN_LINE_FORMAT CON_COLOR_PURPLE "[ WARN] " CON_COLOR_END \
						  "%s", time, FILENAME(file), (line), buf);
				break;
			case e_ERR:
				fprintf(fp, "%s" FUN_LINE_FORMAT CON_COLOR_RED "[ERROR] " CON_COLOR_END \
						  "%s", time, FILENAME(file), (line), buf);
				break;

			default:
				ASSERT(0);
				break;
		}
		fflush(fp);
	}

	return i;
}

int muLuaPrint(FILE *fp, int level, const char *file, 
					const int line, const char *str)
{
	int i = 0;
	char time[64];

	if (NULL == fp)
		return -1;

	if ((e_ERR == level)
		||(debug_lua_level <= level))
	{
		getTime(time, sizeof(time));
		
		switch (level) {
			case e_DEBUG:
				fprintf(fp, "%s" FUN_LINE_LUA_FORMAT CON_COLOR_GREEN "[DEBUG] " CON_COLOR_END \
						  "%s" , time, FILENAME(file), (line), str);
				break;
				
			case e_INFO:
				fprintf(fp, "%s" FUN_LINE_LUA_FORMAT CON_COLOR_YELLOW "[ INFO] " CON_COLOR_END \
						  "%s" , time, FILENAME(file), (line), str);
				break;
			case e_WARN:
				fprintf(fp, "%s" FUN_LINE_LUA_FORMAT CON_COLOR_PURPLE "[ WARN] " CON_COLOR_END \
						  "%s" , time, FILENAME(file), (line), str);
				break;
			case e_ERR:
				fprintf(fp, "%s" FUN_LINE_LUA_FORMAT CON_COLOR_RED "[ERROR] " CON_COLOR_END \
						  "%s" , time, FILENAME(file), (line), str);
				break;

			default:
				ASSERT(0);
				break;
		}
		fflush(fp);
	}

	return i;
}


void debugChange()
{
	setLuaDebugLevel(e_DEBUG);
	setDebugLevel(e_WARN);
	
	static int writing = 0;
	
	if (writing)
		logFileClose();
	else 
		logFileWrite();

	writing = !writing;
}

int setLuaDebugLevel(int level)
{
	debug_lua_level = level;
	return debug_lua_level;
}

int setDebugLevel(int level)
{
	debug_level = level;
	return debug_level;
}

int getDebugLevel(void)
{
	return debug_level;
}


